package task

import (
	"cvevulner/common"
	"cvevulner/models"
	"cvevulner/taskhandler"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/logs"
	"strconv"
	"strings"
	"time"
)

// Verify whether the issue on gitee has been deleted
func CheckIssueIsExist() error {
	defer common.Catchs()
	prnum, prErr := beego.AppConfig.Int("crontab::prcnum")
	if prErr != nil {
		prnum = 100
	}
	// Get the data source of the table
	err := taskhandler.ProcIssueIsExists(prnum)
	logs.Info(err)
	return err
}

// Statistics of issues created in different communities, uncreated issues are created
func CommunityIssueStatist() error {
	// Get the configuration file
	yamlConfigTable := beego.AppConfig.String("cve::yaml_config_table")
	tableList := strings.Split(yamlConfigTable, ",")
	localList := make([][]string, 0)
	cyc := models.GetCommunityYamlConfigAll()
	if len(cyc) > 0 {
		for _, c := range cyc {
			taskhandler.StatistCommunityIssue(c)
		}
	}
	for _, tab := range tableList {
		flag := false
		tabList := strings.Split(tab, ":")
		for _, c := range cyc {
			if tabList[0] == c.TableName {
				flag = true
				break
			}
		}
		if !flag {
			if len(tabList) > 1 {
				localList = append(localList, tabList)
			}
		}
	}
	if len(localList) > 0 {
		for _, lc := range localList {
			organizationID, _ := strconv.Atoi(lc[1])
			cyc := models.CommunityYamlConfig{TableName: lc[0], OrganizationID: int8(organizationID)}
			num, err := models.InsertCommunityYamlConfig(&cyc)
			if err != nil {
				logs.Error("num: ", num, ",err: ", err)
			}
		}
	}
	return nil
}

func IssueLabelCheck() error {
	uNaffected := beego.AppConfig.String("labeUnaffected")
	labelFixed := beego.AppConfig.String("labelFixed")
	labelUnFix := beego.AppConfig.String("labelUnFix")
	templateId := int64(0)
	num := 100
	for {
		issueTemp, issueErr := models.GetIssueTemplateByStatus(3, templateId, num)
		if len(issueTemp) == 0 {
			logs.Error("issueErr", issueErr)
			return issueErr
		}
		for _, issue := range issueTemp {
			templateId = issue.TemplateId
			path := issue.Repo
			if issue.StatusName != "closed" && issue.StatusName != "已完成" {
				logs.Error("issue.StatusName: ", issue.StatusName)
				continue
			}
			affectBrandFlag := false
			cveCenter := models.VulnCenter{CveId: issue.CveId, CveNum: issue.CveNum}
			cveErr := models.GetVulnCenterByCid(&cveCenter, "cve_id", "cve_num")
			if cveErr != nil {
				logs.Error("cveErr: ", cveErr)
				continue
			}
			owner, token := common.GetOwnerAndToken(cveCenter.OrganizationID)
			sn := models.SecurityNotice{CveId: issue.CveId, CveNum: issue.CveNum}
			snErr := sn.Read("cve_id", "cve_num")
			if snErr != nil {
				logs.Error("snErr: ", snErr)
			} else {
				affectBranchsxList := make([]string, 0)
				affectedBranchs := ""
				if cveCenter.OrganizationID == 4 {
					affectedBranchs = strings.ReplaceAll(sn.AffectProduct, "/", ",")
				} else if cveCenter.OrganizationID == 3 {
					if sn.AffectProduct != "" && len(sn.AffectProduct) > 1 {
						tmpTagList := make([]string, 0)
						affectProductSlice := strings.Split(sn.AffectProduct, "/")
						for _, tags := range affectProductSlice {
							mdbt := models.MindSporeBrandTags{PackageName: path, Tags: tags}
							mtErr := models.QueryMindSporeBrandTags(&mdbt, "PackageName", "Tags")
							if mtErr == nil {
								tmpTagList = append(tmpTagList, mdbt.Brand)
							}
						}
						if len(tmpTagList) > 0 {
							sn.AffectProduct = strings.Join(tmpTagList, "/")
							affectedBranchs = strings.ReplaceAll(sn.AffectProduct, "/", ",")
						} else {
							sn.AffectProduct = ""
						}
					}
				} else if cveCenter.OrganizationID == 2 {
					affectedBranchs = strings.ReplaceAll(sn.AffectProduct, "/", ",")
				} else {
					affectedBranchs = beego.AppConfig.String("cve::affected_branchs")
				}
				if affectedBranchs != "" && len(affectedBranchs) > 0 {
					affectBranchsxList = strings.Split(affectedBranchs, ",")
				}
				if sn.AffectProduct != "" && len(sn.AffectProduct) > 1 {
					affectProductList := strings.Split(sn.AffectProduct, "/")
					if len(affectProductList) > 0 {
						for _, brands := range affectProductList {
							if len(affectBranchsxList) > 0 {
								for _, affectBranch := range affectBranchsxList {
									if affectBranch == brands {
										affectBrandFlag = true
										break
									}
								}
							}
							if affectBrandFlag {
								break
							}
						}
					}
				}
				switch issue.IssueStatus {
				case 2:
					sn.AffectStatus = "Fixed"
				case 6:
					sn.AffectStatus = "UnAffected"
				default:
					sn.AffectStatus = "UnFixed"
				}
				err := sn.Update("affect_status")
				if err != nil {
					logs.Error(err)
				}
			}
			if affectBrandFlag {
				issue.IssueLabel = labelFixed
			} else {
				issue.IssueLabel = uNaffected
			}
			labelSlice := make([]string, 0)
			labelSlice = taskhandler.AddLabelValue(token, path, issue.IssueNum, owner, issue.IssueLabel, 2)
			upLabelFlag := false
			if len(labelSlice) > 0 {
				labelStr := strings.Join(labelSlice, ",")
				if affectBrandFlag {
					if strings.Contains(labelStr, uNaffected) {
						labelSlice = common.DeleteSliceValue(labelSlice, uNaffected)
						upLabelFlag = true
					}
				} else {
					if strings.Contains(labelStr, labelFixed) {
						labelSlice = common.DeleteSliceValue(labelSlice, labelFixed)
						upLabelFlag = true
					}
				}
				if strings.Contains(labelStr, labelUnFix) {
					labelSlice = common.DeleteSliceValue(labelSlice, labelUnFix)
					upLabelFlag = true
				}
				issue.IssueLabel = strings.Join(labelSlice, ",")
				issue.CveLevel = models.OpenEulerScoreProc(issue.OpenEulerScore)
				tpErr := models.UpdateIssueTemplate(&issue, "IssueLabel", "CveLevel")
				if tpErr != nil {
					logs.Error(tpErr)
				}
			}
			if upLabelFlag {
				update := taskhandler.UpdateIssueLabels(token, path, issue.IssueNum, owner, issue.IssueLabel)
				if !update {
					logs.Error("update gitee issue label  fail ,", issue.IssueNum, issue.IssueLabel)
				}
			}
		}
	}
}

func GetV8Token() error {
	tokenList := models.QueryAuthTokenInfo()
	if len(tokenList) > 0 {
		for _, tk := range tokenList {
			var giteeToken taskhandler.GiteeTokenInfo
			taskhandler.GiteePostFreshToken(tk.RefreshToken, &giteeToken)
			if len(giteeToken.AccessToken) > 0 {
				tk.AccessToken = giteeToken.AccessToken
				tk.RefreshToken = giteeToken.RefreshToken
				tk.CreatedAt = giteeToken.CreatedAt
				tk.ExpiresIn = giteeToken.ExpiresIn
				tk.Scope = giteeToken.Scope
				tk.TokenType = giteeToken.TokenType
				tk.UpdateTime = common.GetCurTime()
				models.UpdateAuthTokenInfoById(tk)
			}
		}
	}
	return nil
}

func SetIssueProcParams() error {
	prnum, prErr := beego.AppConfig.Int("crontab::prcnum")
	if prErr != nil {
		prnum = 100
	}
	tokenList := models.QueryAuthTokenInfo()
	tokenMap := make(map[int8]models.AuthTokenInfo, len(tokenList))
	if len(tokenList) > 0 {
		for _, tl := range tokenList {
			tokenMap[tl.OrganizationID] = tl
		}
	}
	// 1.Get pending data
	cveId := int64(0)
	for {
		vulnCve, _ := models.QueryAllCveVuln(prnum, cveId)
		if len(vulnCve) > 0 {
			for _, vl := range vulnCve {
				cveId = vl.CveId
				if vl.Status > 2 {
					continue
				}
				its := models.IssueTemplate{CveId: vl.CveId, CveNum: vl.CveNum}
				tmpErr := models.GetIssueTemplateByColName(&its, "CveId", "CveNum")
				if its.TemplateId == 0 {
					logs.Error("tmpErr:", tmpErr)
					continue
				}
				if its.Status > 2 || (len(its.PlanStarted) > 1 && len(its.Deadline) > 1) {
					continue
				}
				authToken := tokenMap[vl.OrganizationID]
				taskhandler.GetEntIssueDetail(vl, &its)
				if len(its.PlanStarted) > 1 && len(its.Deadline) > 1 {
					its.UpdateTime = time.Now()
					models.UpdateIssueTemplate(&its, "PlanStarted", "Deadline", "UpdateTime")
					continue
				}
				if its.NVDScore > 0 {
					cveLevel := models.OpenEulerScoreProc(its.NVDScore)
					deadLine := taskhandler.CvePlanCloseTime(its.CreateTime, cveLevel, true)
					planAt := common.GetSpecifiedTime(its.CreateTime, 0, false, true)
					priority := taskhandler.GetIssuePriority(cveLevel)
					taskhandler.UpdateEntIssueDetail(authToken.EnId, its.IssueId,
						authToken.AccessToken, planAt, deadLine, priority)
				}
			}
		} else {
			break
		}
	}
	return nil
}
